﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;
using System.IO;

namespace Biotech.Utils
{
    public class UnitIni
    {

#region 引用DLL

        /// <summary>
        /// 读取ini配置文件
        /// </summary>
        /// <param name="sectionName">要读取的section名,如果传入null获取ini文件所有的section名</param>
        /// <param name="key">要读取的key,如果传入null获取此section名下的所有key</param>
        /// <param name="defaultValue">读取异常的情况下的缺省值</param>
        /// <param name="returnBuffer">key所对应的值，如果该key不存在则返回defaultValue</param>
        /// <param name="size">值允许的大小</param>
        /// <param name="filePath">ini文件的完整路径和文件名</param>
        /// <see cref="https://msdn.microsoft.com/zh-cn/library/ms724353.aspx"/>
        /// <returns></returns>
        [DllImport("kernel32", CharSet=CharSet.Unicode)]
        private static extern int GetPrivateProfileString(string sectionName, string key, string defaultValue, byte[] returnBuffer, int size, string filePath);

        /// <summary>
        /// 读
        /// </summary>
        /// <param name="section">INI文件中的段落名称</param>
        /// <param name="key">INI文件中的关键字</param>
        /// <param name="def">无法读取时候时候的缺省数值</param>
        /// <param name="retVal">读取数值</param>
        /// <param name="size">数值的大小</param>
        /// <param name="filePath">INI文件的完整路径和名称</param>
        /// <returns></returns>
        [DllImport("kernel32", CharSet = CharSet.Unicode)]
        private static extern int GetPrivateProfileString(string section, string key, string def, StringBuilder retVal, int size, string filePath);


        /// <summary>
        /// 写入ini配置文件
        /// </summary>
        /// <param name="sectionName">要写入的section名</param>
        /// <param name="key">要写入的key，如果传入为null，整个sectionName被清除</param>
        /// <param name="value">key所对应的值，如果传入为null，此key将被清除</param>
        /// <param name="filePath">ini文件的完整路径和文件名</param>
        /// <see cref="https://msdn.microsoft.com/zh-cn/library/ms725501.aspx"/>
        /// <returns></returns>
        [DllImport("kernel32")]
        private static extern long WritePrivateProfileString(string sectionName, string key, string value, string filePath);



        /// <summary>
        /// 获取某个指定节点(Section)中所有KEY和Value
        /// </summary>
        /// <param name="lpAppName">节点名称</param>
        /// <param name="lpReturnedString">返回值的内存地址,每个之间用\0分隔</param>
        /// <param name="nSize">内存大小(characters)</param>
        /// <param name="lpFileName">Ini文件</param>
        /// <returns>内容的实际长度,为0表示没有内容,为nSize-2表示内存大小不够</returns>
        [DllImport("kernel32.dll", CharSet = CharSet.Auto)]
        private static extern uint GetPrivateProfileSection(string lpAppName, IntPtr lpReturnedString, uint nSize, string lpFileName);

        #endregion
        /// <summary>
        /// 取得一个文本文件流的编码方式。
        /// </summary>
        /// <param name="stream">文本文件流。</param>
        /// <returns></returns>
        public static Encoding GetEncoding(FileStream stream)
        {
            return GetEncoding(stream, Encoding.Default);
        }

        /// <summary>
        /// 取得一个文本文件的编码方式。如果无法在文件头部找到有效的前导符，Encoding.Default将被返回。
        /// </summary>
        /// <param name="fileName">文件名。</param>
        /// <returns></returns>
        public static Encoding GetEncoding(string fileName)
        {
            return GetEncoding(fileName, Encoding.Default);
        }

        /// <summary>
        /// 取得一个文本文件的编码方式。
        /// </summary>
        /// <param name="fileName">文件名。</param>
        /// <param name="defaultEncoding">默认编码方式。当该方法无法从文件的头部取得有效的前导符时，将返回该编码方式。</param>
        /// <returns></returns>
        public static Encoding GetEncoding(string fileName, Encoding defaultEncoding)
        {
            FileStream fs = new FileStream(fileName, FileMode.Open);
            Encoding targetEncoding = GetEncoding(fs, defaultEncoding);
            fs.Close();
            return targetEncoding;
        }

        /// <summary>
        /// 取得一个文本文件流的编码方式。
        /// </summary>
        /// <param name="stream">文本文件流。</param>
        /// <param name="defaultEncoding">默认编码方式。当该方法无法从文件的头部取得有效的前导符时，将返回该编码方式。</param>
        /// <returns></returns>
        public static Encoding GetEncoding(FileStream stream, Encoding defaultEncoding)
        {
            Encoding targetEncoding = defaultEncoding;
            if (stream != null && stream.Length >= 2)
            {
                //保存文件流的前4个字节
                byte byte1 = 0;
                byte byte2 = 0;
                byte byte3 = 0;
                byte byte4 = 0;
                //保存当前Seek位置
                long origPos = stream.Seek(0, SeekOrigin.Begin);
                stream.Seek(0, SeekOrigin.Begin);

                int nByte = stream.ReadByte();
                byte1 = Convert.ToByte(nByte);
                byte2 = Convert.ToByte(stream.ReadByte());
                if (stream.Length >= 3)
                {
                    byte3 = Convert.ToByte(stream.ReadByte());
                }
                if (stream.Length >= 4)
                {
                    byte4 = Convert.ToByte(stream.ReadByte());
                }

                //根据文件流的前4个字节判断Encoding
                //Unicode {0xFF, 0xFE};
                //BE-Unicode {0xFE, 0xFF};
                //UTF8 = {0xEF, 0xBB, 0xBF};
                if (byte1 == 0xFE && byte2 == 0xFF)//UnicodeBe
                {
                    targetEncoding = Encoding.BigEndianUnicode;
                }
                if (byte1 == 0xFF && byte2 == 0xFE && byte3 != 0xFF)//Unicode
                {
                    targetEncoding = Encoding.Unicode;
                }
                if (byte1 == 0xEF && byte2 == 0xBB && byte3 == 0xBF)//UTF8
                {
                    targetEncoding = Encoding.UTF8;
                }

                //恢复Seek位置     
                stream.Seek(origPos, SeekOrigin.Begin);
            }
            return targetEncoding;
        }

        /// <summary>
        /// 获取ini文件内所有的section名称(遇到中文字符要转码)
        /// </summary>
        /// <param name="filePath">文件路径</param>
        /// <returns>返回一个包含section名称的集合</returns>
        public static List<string> GetSectionNames(string filePath)
        {
            byte[] buffer = new byte[2048];
            int length = GetPrivateProfileString(null, "", "", buffer, 999, filePath);
            string[] SectionsArry = Encoding.Unicode.GetString(buffer).Split(new string[] { "\0" }, StringSplitOptions.RemoveEmptyEntries);
            return SectionsArry.ToList();
        }

 
        public static List<string> ReadKeys(string SectionName, string iniFilename)
        {
            List<string> result = new List<string>();
            Byte[] buf = new Byte[65536];
            int len = GetPrivateProfileString(SectionName, null, null, buf, buf.Length, iniFilename);
            int j = 0;
            for (int i = 0; i < len; i++)
                if (buf[i] == 0)
                {
                    result.Add(Encoding.Default.GetString(buf, j, i - j));
                    j = i + 1;
                }
            return result;
        }

        /// <summary>
        /// 获取INI文件中指定节点(Section)中的所有条目
        /// </summary>
        /// <param name="iniFile">Ini文件</param>
        /// <param name="section">节点名称</param>
        /// <returns>指定节点中的所有项目,没有内容返回string[0]</returns>
        public static string[] INIGetAllItems(string iniFile, string section)
        {
            //返回值形式为 key=value,例如 Color=Red
            uint MAX_BUFFER = 32767;    //默认为32767
            string[] items = new string[0];      //返回值
            //分配内存
            IntPtr pReturnedString = Marshal.AllocCoTaskMem((int)MAX_BUFFER * sizeof(char));
            uint bytesReturned = GetPrivateProfileSection(section, pReturnedString, MAX_BUFFER, iniFile);
            if (!(bytesReturned == MAX_BUFFER - 2) || (bytesReturned == 0))
            {
                string returnedString = Marshal.PtrToStringAuto(pReturnedString, (int)bytesReturned);
                items = returnedString.Split(new char[] { '\0' }, StringSplitOptions.RemoveEmptyEntries);
            }
            Marshal.FreeCoTaskMem(pReturnedString);     //释放内存
            return items;
        }



        public UnitIni() { }
    
        /// <summary>
        /// 构造方法
        /// </summary>
        /// <param name="INIPath">文件路径</param>
        public UnitIni(string Path)
        {
            UnitIni.Path = Path;
        }
    
     #region 类的对象
        private static string Path = "";
    
        /// <summary>
        /// 读
        /// </summary>
        /// <param name="section">项目名称(如 [TypeName] )</param>
        /// <param name="key">键</param>
        /// <returns></returns>
        public string GetValue(string section, string key)
        {
            string result = "";
            try
            {
                result = GetValue(section, key, Path);
            }
            catch (Exception)
            {
            }
            return result;
        }
     
        /// <summary>
        /// 写
        /// </summary>
        /// <param name="section">项目名称(如 [TypeName] )</param>
        /// <param name="key">键</param>
        /// <param name="val">值</param>
        /// <returns></returns>
        public bool SetValue(string section, string key, string val)
        {
            bool resultFlag = false;
            try
            {
                resultFlag = SetValue(section, key, val, Path);
            }
            catch (Exception)
            {
            }
            return resultFlag;
        }

        #endregion

        #region 类 静态

        /// <summary>
        /// 获取节点值(string)
        /// </summary>
        /// <param name="SectionName"></param>
        /// <param name="Key"></param>
        /// <param name="DefaultValue">默认值</param>
        /// <param name="FileName"></param>
        /// <returns></returns>
        public static string GetValue(string SectionName, string Key, string DefaultValue, string FileName)
        {
            StringBuilder Builder = new StringBuilder(1024);
            try
            {
                GetPrivateProfileString(SectionName, Key, "", Builder, 1024, FileName);
                if (Builder.ToString() == "")
                {
                    Builder.Append(DefaultValue);
                    SetValue(SectionName, Key, "", FileName);
                }
            }
            catch (Exception)
            {
                throw;
            }
            return Builder.ToString();
        }

        /// <summary>
        /// 功能: 获取节点的值
        /// </summary>
        /// <param name="section">项目名称(如 [TypeName] )</param>
        /// <param name="key">键</param>
        /// <param name="file"></param>
        /// <returns></returns>
        public static string GetValue(string section, string key, string file)
        {
            StringBuilder builder = new StringBuilder(1024);
            try
            {
                GetPrivateProfileString(section, key, "", builder, 1024, file);
                if (builder.ToString() == "")
                {
                    SetValue(section, key, "", file);
                }
            }
            catch (Exception)
            {
            }
            return builder.ToString();
        }
    
        /// <summary>
        /// 功能: 给节点赋值
        /// </summary>
        /// <param name="section">项目名称(如 [TypeName] )</param>
        /// <param name="key">键</param>
        /// <param name="val">值</param>
        /// <param name="file"></param>
        /// <returns></returns>
        public static bool SetValue(string section, string key, string val, string file)
        {
            try
            {
                WritePrivateProfileString(section, key, val, file);
                return true;
            }
            catch (Exception)
            {
                return false;
            }
        }

#endregion

        /// <summary>
        /// 创建INI配置文件
        /// </summary>
        /// <param name="fileName">ini配置文件名称</param>
        /// <returns>返回一个状态值 100成功创建 200创建失败</returns>
        public static string CreateIni(string fileName)
        {
            try
            {
                if (!Directory.Exists(Path))
                {
                    Directory.CreateDirectory(Path);
                }
                string filePath = Path + "\\" + fileName;
        
                if (File.Exists(filePath))
                {
                    File.Delete(filePath);
                }
                File.Create(filePath).Close();
                return "100";//成功创建
            }
            catch (Exception)
            {
                return "200";//创建失败
            }
        }

        /// <summary>
        /// 验证文件是否存在
        /// </summary>
        /// <returns>布尔值</returns>
        public static bool ExistINIFile()
        {
            return File.Exists(Path);
        }


        /// <summary>
        /// 移除指定的section
        /// </summary>
        /// <param name="SectionName">section名称</param>
        /// <param name="filePath">文件路径</param>
        /// <returns></returns>
        public static bool RemoveSection(string SectionName, string filePath)
        {
            try
            {
                int rs = (int)WritePrivateProfileString(SectionName, null, "", filePath);
                return rs > 0;
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }

    }
}
